package com.me.study.javaCore.dynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedHashMap;
import java.util.Map;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * JDK 和 CGLIB 的性能比对:
 *  在1.6和1.7的时候，JDK动态代理的速度要比CGLib动态代理的速度要慢。
 *  在JDK1.8的时候，JDK动态代理的速度已经比CGLib动态代理的速度快很多。
 *
 * @author ME
 * @date   2020/4/1
 */
public class TestProxyPerformance {

    public static void main(String[] args) {
        // 创建测试对象
        ITarget target = new TargetImpl();

        // JDK动态代理
        ITarget dynamicProxy = (ITarget) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return method.invoke(target, args);
            }
        });

        // CGLIB 动态代理
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                return methodProxy.invokeSuper(obj, args);
            }
        });
        ITarget cglibProxy = (ITarget) enhancer.create();

        //预热一下
        int preRunCount = 10000;
        runWithoutMonitor(target, preRunCount);
        runWithoutMonitor(cglibProxy, preRunCount);
        runWithoutMonitor(dynamicProxy, preRunCount);

        //执行测试
        Map<String, ITarget> tests = new LinkedHashMap<String, ITarget>();
        tests.put("Native   ", target);
        tests.put("Dynamic  ", dynamicProxy);
        tests.put("Cglib    ", cglibProxy);
        int repeatCount = 3;
        int runCount = 1000000;
        runTest(repeatCount, runCount, tests);
        runCount = 50000000;
        runTest(repeatCount, runCount, tests);
    }

    private static void runTest(int repeatCount, int runCount, Map<String, ITarget> tests) {
        System.out.println(
            String.format("\n===== run test : [repeatCount=%s] [runCount=%s] [java.version=%s] =====",
                repeatCount, runCount, System.getProperty("java.version")));
        for (int i = 0; i < repeatCount; i++) {
            System.out.println(String.format("\n--------- test : [%s] ---------", (i + 1)));
            for (String key : tests.keySet()) {
                runWithMonitor(tests.get(key), runCount, key);
            }
        }
    }

    private static void runWithoutMonitor(ITarget target, int runCount) {
        for (int i = 0; i < runCount; i++) {
            target.doSome(i);
        }
    }

    private static void runWithMonitor(ITarget target, int runCount, String tag) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < runCount; i++) {
            target.doSome(i);
        }
        long end = System.currentTimeMillis();
        System.out.println("[" + tag + "] Total Time:" + (end - start) + "ms");
    }

}
